import 'dart:convert';
import 'dart:typed_data';

import 'package:chisa/dictionary/dictionary_entry.dart';
import 'package:chisa/media/media_history_items/media_history_item.dart';

class DictionarySearchResult {
  DictionarySearchResult({
    required this.dictionaryName,
    required this.formatName,
    required this.originalSearchTerm,
    required this.fallbackSearchTerms,
    required this.entries,
    this.mediaHistoryItem,
    this.storeReference,
  });

  /// The dictionary where the results were sourced from.
  final String dictionaryName;

  /// The format of the dictionary where the results were sourced from.
  final String formatName;

  /// An original search term used from the actual media or search made.
  String originalSearchTerm;

  /// A list of fallback search terms to be used in the database query.
  /// Generated by a [Language] beforehand.
  List<String> fallbackSearchTerms;

  final MediaHistoryItem? mediaHistoryItem;

  /// The list of processed search results.
  List<DictionaryEntry> entries;

  /// An ObjectBox [Store] reference that is used to make the dictionary
  /// search from another isolate. As an empty [DictionarySearchResult] is
  /// passed as a parameter to make the search, the object itself to be filled
  /// is passed as the parameter to the [compute] function.
  ByteData? storeReference;

  /// Get a serialised representation of the dictionary search result
  /// for history and persistence purposes.
  String toJson() {
    List<String> serialisedItems = [];
    for (DictionaryEntry entry in entries) {
      serialisedItems.add(
        entry.toJson(),
      );
    }

    Map<String, dynamic> map = {
      "dictionaryName": dictionaryName,
      "formatName": formatName,
      "originalSearchTerm": originalSearchTerm,
      "fallbackSearchTerms": jsonEncode(fallbackSearchTerms),
      "entries": jsonEncode(serialisedItems),
    };

    if (mediaHistoryItem != null) {
      map["mediaHistoryItem"] = mediaHistoryItem!.toJson();
    }

    return jsonEncode(map);
  }

  factory DictionarySearchResult.fromJson(String json) {
    Map<String, dynamic> map = Map.castFrom(jsonDecode(json));

    List<String> entriesJson = List.castFrom(jsonDecode(map["entries"]));
    List<String> fallbackSearchTerms =
        List.castFrom(jsonDecode(map["fallbackSearchTerms"]));

    List<DictionaryEntry> entries = [];
    for (String entryJson in entriesJson) {
      entries.add(
        DictionaryEntry.fromJson(entryJson),
      );
    }

    MediaHistoryItem? mediaHistoryItem;
    String? itemJson = map["mediaHistoryItem"];
    if (itemJson != null && itemJson.isNotEmpty) {
      mediaHistoryItem = MediaHistoryItem.fromJson(itemJson);
    }

    return DictionarySearchResult(
      dictionaryName: map["dictionaryName"],
      formatName: map["formatName"],
      originalSearchTerm: map["originalSearchTerm"],
      fallbackSearchTerms: fallbackSearchTerms,
      entries: entries,
      mediaHistoryItem: mediaHistoryItem,
    );
  }
}
